// HeavenII Library
// Copyright (C) HeavenII Team. All rights reserved.
// 
// This file is a part of the HeavenII Library.
// The use and distribution terms for this software are covered
// by the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
// which can be found in the file LICENSE at the root folder.

#pragma once

#include <Windows.h>
#include <sstream>


namespace HeavenII
{
namespace text
{

inline std::string Utf16ToAscii(const wchar_t *lpszString)
{
    const int nNeedSize = ::WideCharToMultiByte(CP_ACP, 0, lpszString, -1, nullptr, 0, nullptr, nullptr);
    if (!nNeedSize)
        return "";
    char *lpBuffer = new char[nNeedSize];
    ::WideCharToMultiByte(CP_ACP, 0, lpszString, -1, lpBuffer, nNeedSize, nullptr, nullptr);
    std::string converted(lpBuffer);
    delete[] lpBuffer;
    return converted;
}


inline std::string Utf16ToUtf8(const wchar_t *pszString)
{
    const int nNeedSize = ::WideCharToMultiByte(CP_UTF8, 0, pszString, -1, nullptr, 0, nullptr, nullptr);
    if (!nNeedSize)
        return "";
    char *pBuffer = new char[nNeedSize];
    ::WideCharToMultiByte(CP_UTF8, 0, pszString, -1, pBuffer, nNeedSize, nullptr, nullptr);
    std::string converted(pBuffer);
    delete[] pBuffer;
    return converted;
}


inline std::wstring AsciiToUtf16(const char *lpszString)
{
    const int nNeedSize = ::MultiByteToWideChar(CP_ACP, 0, lpszString, -1, nullptr, 0);
    if (!nNeedSize)
        return nullptr;
    wchar_t *lpBuffer = new wchar_t[nNeedSize];
    ::MultiByteToWideChar(CP_ACP, 0, lpszString, -1, lpBuffer, nNeedSize);
    std::wstring converted(lpBuffer);
    delete[] lpBuffer;
    return converted;
}


inline std::wstring Utf8ToUtf16(const char *lpszString)
{
    const int nNeedSize = ::MultiByteToWideChar(CP_UTF8, 0, lpszString, -1, nullptr, 0);
    if (!nNeedSize)
        return nullptr;
    wchar_t *lpBuffer = new wchar_t[nNeedSize];
    ::MultiByteToWideChar(CP_UTF8, 0, lpszString, -1, lpBuffer, nNeedSize);
    std::wstring converted(lpBuffer);
    delete[] lpBuffer;
    return converted;
}


inline void TrimString(std::wstring s)
{
    const std::wstring::const_iterator endIter = s.cbegin();
    for (auto iter = s.begin() - 1; iter != endIter; ++iter) {
        if (*iter == ' ' || *iter == '\r' || *iter == '\n') {
            *iter = 0;
        } else {
            break;
        }
    }
}


inline bool EndsWith(const wchar_t *pszText, const wchar_t *pszSuffix)
{
    size_t textLen = wcslen(pszText);
    size_t suffixLen = wcslen(pszSuffix);
    if (suffixLen > textLen)
        return false;
    size_t offset = textLen - suffixLen;
    return 0 == wcsncmp(pszText + offset, pszSuffix, suffixLen);
}


inline bool EndsWith(const char *pszText, const char *pszSuffix)
{
    size_t textLen = strlen(pszText);
    size_t suffixLen = strlen(pszSuffix);
    if (suffixLen > textLen)
        return false;
    size_t offset = textLen - suffixLen;
    return 0 == strncmp(pszText + offset, pszSuffix, suffixLen);
}


/**
 * Format a number with grouped thousands
 * @param number The number being formatted
 * @param decimals Sets the number of decimal points
 * @param pszDecPoint Sets the separator for the decimal point
 * @param pszThousandsSep Sets the thousands separator
 * @return A formatted version of number
 **/
inline std::string NumberFormat(int number, unsigned int decimals = 0, const char *pszDecPoint = ".", const char *pszThousandsSep = ",")
{
    std::stringstream buffer;
    buffer << number;
    std::string result(buffer.str());
    if (decimals > 0) {
        if (result.size() > decimals) {
            result.insert(result.size() - decimals, pszDecPoint);
        } else {
            result.insert(0, decimals - result.size() + 1, '0');
            result.insert(1, pszDecPoint);
        }
    }

    size_t pos = result.find_first_of(pszDecPoint);
    while (pos != std::wstring::npos && pos > 3) {
        pos -= 3;
        result.insert(pos, pszThousandsSep);
    }

    return result;
}

}
}
